package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

func main() {
	// 初始化随机数种子
	rand.Seed(time.Now().UnixNano())

	// ==========================================
	// Goroutine 基础
	// ==========================================

	// 创建一个简单的goroutine
	go sayHello1()

	// 使用匿名函数创建goroutine
	go func() {
		fmt.Println("这是一个匿名函数goroutine")
	}()

	// 带参数的goroutine
	go sayMessage("你好，Go并发！")

	// 主goroutine等待一下，让其他goroutine有时间执行
	// 注意：这不是同步goroutine的好方法，仅用于演示
	time.Sleep(100 * time.Millisecond)

	// ==========================================
	// 使用WaitGroup同步goroutine
	// ==========================================

	fmt.Println("\n=== 使用WaitGroup同步goroutine ===")

	var wg sync.WaitGroup

	// 添加3个等待的goroutine
	wg.Add(3)

	// 启动3个goroutine
	for i := 1; i <= 3; i++ {
		go func(id int) {
			defer wg.Done() // 完成时减少计数
			fmt.Printf("Goroutine %d 开始工作\n", id)
			time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
			fmt.Printf("Goroutine %d 工作完成\n", id)
		}(i)
	}

	// 等待所有goroutine完成
	wg.Wait()
	fmt.Println("所有goroutine已完成")

	// ==========================================
	// Channel 基础
	// ==========================================

	fmt.Println("\n=== Channel基础 ===")

	// 创建一个无缓冲的channel
	ch := make(chan string)

	// 在goroutine中发送数据
	go func() {
		ch <- "Hello from channel!" // 发送数据到channel
	}()

	// 从channel接收数据
	message := <-ch
	fmt.Println(message)

	// ==========================================
	// 带缓冲的Channel
	// ==========================================

	fmt.Println("\n=== 带缓冲的Channel ===")

	// 创建一个容量为3的缓冲channel
	bufferedCh := make(chan int, 3)

	// 发送数据到缓冲channel
	bufferedCh <- 1
	bufferedCh <- 2
	bufferedCh <- 3

	// 接收数据
	fmt.Println(<-bufferedCh)
	fmt.Println(<-bufferedCh)
	fmt.Println(<-bufferedCh)

	// ==========================================
	// Channel方向
	// ==========================================

	fmt.Println("\n=== Channel方向 ===")

	// 创建一个双向channel
	dataCh := make(chan int)

	// 启动发送者和接收者goroutine
	go sender(dataCh)
	go receiver(dataCh)

	// 等待一下
	time.Sleep(100 * time.Millisecond)

	// ==========================================
	// 关闭Channel和遍历
	// ==========================================

	fmt.Println("\n=== 关闭Channel和遍历 ===")

	// 创建一个channel
	numberCh := make(chan int)

	// 启动发送者goroutine
	go func() {
		for i := 1; i <= 5; i++ {
			numberCh <- i
		}
		close(numberCh) // 关闭channel
	}()

	// 使用for-range遍历channel
	for num := range numberCh {
		fmt.Printf("接收到: %d\n", num)
	}

	// ==========================================
	// Select语句
	// ==========================================

	fmt.Println("\n=== Select语句 ===")

	// 创建两个channel
	ch1 := make(chan string)
	ch2 := make(chan string)

	// 在goroutine中发送数据
	go func() {
		time.Sleep(50 * time.Millisecond)
		ch1 <- "来自channel 1的消息"
	}()

	go func() {
		time.Sleep(30 * time.Millisecond)
		ch2 <- "来自channel 2的消息"
	}()

	// 使用select监听多个channel
	for i := 0; i < 2; i++ {
		select {
		case msg1 := <-ch1:
			fmt.Println(msg1)
		case msg2 := <-ch2:
			fmt.Println(msg2)
		}
	}

	// ==========================================
	// Select超时处理
	// ==========================================

	fmt.Println("\n=== Select超时处理 ===")

	// 创建一个channel
	resultCh := make(chan string)

	// 启动一个可能会超时的操作
	go func() {
		// 模拟耗时操作
		time.Sleep(200 * time.Millisecond)
		resultCh <- "操作完成"
	}()

	// 使用select实现超时
	select {
	case result := <-resultCh:
		fmt.Println(result)
	case <-time.After(100 * time.Millisecond):
		fmt.Println("操作超时")
	}

	// ==========================================
	// 使用互斥锁(Mutex)
	// ==========================================

	fmt.Println("\n=== 使用互斥锁 ===")

	// 创建一个计数器
	counter := 0
	var mu sync.Mutex
	var wg2 sync.WaitGroup

	// 启动10个goroutine，每个增加计数器1000次
	for i := 0; i < 10; i++ {
		wg2.Add(1)
		go func() {
			defer wg2.Done()

			for j := 0; j < 1000; j++ {
				mu.Lock()
				counter++
				mu.Unlock()
			}
		}()
	}

	// 等待所有goroutine完成
	wg2.Wait()
	fmt.Printf("计数器最终值: %d\n", counter)

	// ==========================================
	// 使用读写锁(RWMutex)
	// ==========================================

	fmt.Println("\n=== 使用读写锁 ===")

	// 创建一个共享的map
	sharedData := make(map[int]int)
	var rwMu sync.RWMutex
	var wg3 sync.WaitGroup

	// 启动10个写入goroutine
	for i := 0; i < 10; i++ {
		wg3.Add(1)
		go func(id int) {
			defer wg3.Done()

			rwMu.Lock() // 写锁
			sharedData[id] = id * 10
			rwMu.Unlock()

			time.Sleep(10 * time.Millisecond)
		}(i)
	}

	// 启动20个读取goroutine
	for i := 0; i < 20; i++ {
		wg3.Add(1)
		go func() {
			defer wg3.Done()

			for j := 0; j < 5; j++ {
				rwMu.RLock() // 读锁
				for k, v := range sharedData {
					_ = k
					_ = v
					// 只是读取，不做任何操作
				}
				rwMu.RUnlock()

				time.Sleep(5 * time.Millisecond)
			}
		}()
	}

	// 等待所有goroutine完成
	wg3.Wait()
	fmt.Printf("共享map的大小: %d\n", len(sharedData))

	// ==========================================
	// 使用Once确保函数只执行一次
	// ==========================================

	fmt.Println("\n=== 使用Once ===")

	var once sync.Once
	var wg4 sync.WaitGroup

	// 启动5个goroutine，但初始化函数只会执行一次
	for i := 0; i < 5; i++ {
		wg4.Add(1)
		go func(id int) {
			defer wg4.Done()

			once.Do(func() {
				fmt.Printf("初始化函数由goroutine %d执行\n", id)
			})

			fmt.Printf("Goroutine %d完成\n", id)
		}(i)
	}

	// 等待所有goroutine完成
	wg4.Wait()

	// ==========================================
	// 工作池模式
	// ==========================================

	fmt.Println("\n=== 工作池模式 ===")

	const numJobs = 10
	const numWorkers = 3

	// 创建任务和结果channel
	jobs := make(chan int, numJobs)
	results := make(chan int, numJobs)

	// 启动工作者
	var wg5 sync.WaitGroup
	for w := 1; w <= numWorkers; w++ {
		wg5.Add(1)
		go worker(w, jobs, results, &wg5)
	}

	// 发送任务
	for j := 1; j <= numJobs; j++ {
		jobs <- j
	}
	close(jobs)

	// 等待所有工作者完成
	go func() {
		wg5.Wait()
		close(results)
	}()

	// 收集结果
	for result := range results {
		fmt.Printf("收到结果: %d\n", result)
	}

	// ==========================================
	// 使用Context取消操作
	// ==========================================

	fmt.Println("\n=== 使用Context取消操作 ===")

	// 这个例子在08_error_handling.go中有更详细的介绍

	// ==========================================
	// 并发模式：扇入(Fan-in)
	// ==========================================

	fmt.Println("\n=== 并发模式：扇入 ===")

	// 创建两个输入channel
	input1 := make(chan int)
	input2 := make(chan int)

	// 启动两个发送者
	go func() {
		for i := 1; i <= 3; i++ {
			input1 <- i
			time.Sleep(50 * time.Millisecond)
		}
		close(input1)
	}()

	go func() {
		for i := 10; i <= 12; i++ {
			input2 <- i
			time.Sleep(100 * time.Millisecond)
		}
		close(input2)
	}()

	// 合并输入
	merged := fanIn(input1, input2)

	// 接收合并后的结果
	for val := range merged {
		fmt.Printf("接收到: %d\n", val)
	}

	// ==========================================
	// 并发模式：扇出(Fan-out)
	// ==========================================

	fmt.Println("\n=== 并发模式：扇出 ===")

	// 创建输入和输出channel
	tasks := make(chan int, 10)
	processors := 3

	// 发送任务
	for i := 1; i <= 10; i++ {
		tasks <- i
	}
	close(tasks)

	// 启动多个处理者
	var wg6 sync.WaitGroup
	for p := 1; p <= processors; p++ {
		wg6.Add(1)
		go func(id int) {
			defer wg6.Done()

			for task := range tasks {
				// 模拟处理任务
				time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
				fmt.Printf("处理者 %d 处理了任务 %d\n", id, task)
			}
		}(p)
	}

	// 等待所有处理者完成
	wg6.Wait()

	// ==========================================
	// 练习
	// ==========================================

	// 1. 创建一个程序，使用goroutine并行计算一个大数组的和

	// 2. 实现一个简单的生产者-消费者模式，使用channel传递数据

	// 3. 使用select语句实现一个简单的超时机制

	// 4. 实现一个并发安全的计数器，使用互斥锁保护共享状态

	// 5. 创建一个工作池，处理一系列任务，并收集结果
}

// ==========================================
// 辅助函数
// ==========================================

// 简单的goroutine函数
func sayHello1() {
	fmt.Println("Hello, Goroutine!")
}

// 带参数的goroutine函数
func sayMessage(message string) {
	fmt.Println(message)
}

// 只发送数据的函数
func sender(ch chan<- int) {
	for i := 1; i <= 3; i++ {
		ch <- i
		fmt.Printf("发送: %d\n", i)
	}
}

// 只接收数据的函数
func receiver(ch <-chan int) {
	for i := 1; i <= 3; i++ {
		val := <-ch
		fmt.Printf("接收: %d\n", val)
	}
}

// 工作者函数
func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
	defer wg.Done()

	for job := range jobs {
		fmt.Printf("工作者 %d 开始处理任务 %d\n", id, job)
		// 模拟工作
		time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)
		// 发送结果
		results <- job * 2
		fmt.Printf("工作者 %d 完成任务 %d\n", id, job)
	}
}

// 扇入函数：合并多个channel的输出到一个channel
func fanIn(input1, input2 <-chan int) <-chan int {
	output := make(chan int)

	// 启动两个goroutine，分别从input1和input2读取
	go func() {
		for val := range input1 {
			output <- val
		}
	}()

	go func() {
		for val := range input2 {
			output <- val
		}
	}()

	// 当两个输入channel都关闭后，关闭输出channel
	go func() {
		// 这里简化处理，实际上应该等待上面两个goroutine完成
		time.Sleep(500 * time.Millisecond)
		close(output)
	}()

	return output
}

// ==========================================
// 练习参考实现
// ==========================================

// 1. 并行计算数组和
func parallelSum(numbers []int, numGoroutines int) int {
	// 创建一个channel来接收部分和
	partialSums := make(chan int)

	// 计算每个goroutine处理的元素数量
	size := len(numbers) / numGoroutines

	// 启动goroutines
	for i := 0; i < numGoroutines; i++ {
		// 计算每个goroutine的起始和结束索引
		start := i * size
		end := start + size
		if i == numGoroutines-1 {
			end = len(numbers) // 最后一个goroutine处理剩余的所有元素
		}

		go func(start, end int) {
			sum := 0
			for j := start; j < end; j++ {
				sum += numbers[j]
			}
			partialSums <- sum
		}(start, end)
	}

	// 收集并合并结果
	totalSum := 0
	for i := 0; i < numGoroutines; i++ {
		totalSum += <-partialSums
	}

	return totalSum
}

// 2. 生产者-消费者模式
func producerConsumerExample() {
	// 创建一个带缓冲的channel
	queue := make(chan int, 10)
	done := make(chan bool)

	// 启动生产者
	go func() {
		for i := 1; i <= 20; i++ {
			queue <- i
			fmt.Printf("生产: %d\n", i)
			time.Sleep(100 * time.Millisecond)
		}
		close(queue)
	}()

	// 启动消费者
	go func() {
		for item := range queue {
			fmt.Printf("消费: %d\n", item)
			time.Sleep(200 * time.Millisecond)
		}
		done <- true
	}()

	// 等待消费者完成
	<-done
}

// 4. 并发安全的计数器
type SafeCounter struct {
	mu    sync.Mutex
	count int
}

func (c *SafeCounter) Increment() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.count++
}

func (c *SafeCounter) Value() int {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.count
}
